/**
 * Moondance UML modeling tool
 * 
 * This program is free software; you can redistribute it and
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package ro.pub.cs.se.moondance.command;

import java.util.Iterator;
import java.util.List;

import org.eclipse.gef.commands.Command;

import ro.pub.cs.se.moondance.model.Connection;
import ro.pub.cs.se.moondance.model.ModelElement;
import ro.pub.cs.se.moondance.model.UMLDiagram;
import ro.pub.cs.se.moondance.model.UMLStartState;
import ro.pub.cs.se.moondance.model.UMLStateMachine;

/**
 * A command to remove a shape from its parent. The command can be undone or
 * redone.
 */
public class StartStateDeleteCommand extends Command {
	/** Shape to remove. */
	private final UMLStartState child;

	/** ShapeDiagram to remove from. */
	private final ModelElement parent;

	/** Holds a copy of the outgoing connections of child. */
	private List<Connection> sourceConnections;

	/** Holds a copy of the incoming connections of child. */
	private List<Connection> targetConnections;

	/** True, if child was removed from its parent. */
	private boolean wasRemoved;

	/**
	 * Create a command that will remove the shape from its parent.
	 * 
	 * @param parent
	 *            the UMLDiagram containing the child
	 * @param child
	 *            the Shape to remove
	 * @throws IllegalArgumentException
	 *             if any parameter is null
	 */
	public StartStateDeleteCommand(ModelElement parent, UMLStartState child) {
		if (parent == null || child == null) {
			throw new IllegalArgumentException();
		}
		setLabel("shape deletion");
		this.parent = parent;
		this.child = child;
	}

	/**
	 * Reconnects a List of Connections with their previous endpoints.
	 * 
	 * @param connections
	 *            a non-null List of connections
	 */
	private void addConnections(List<Connection> connections) {
		for (Iterator<Connection> iter = connections.iterator(); iter.hasNext();) {
			Connection conn = iter.next();
			conn.reconnect();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.commands.Command#canUndo()
	 */
	public boolean canUndo() {
		return wasRemoved;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.commands.Command#execute()
	 */
	public void execute() {
		// store a copy of incoming & outgoing connections before proceeding
		sourceConnections = child.getSourceConnections();
		targetConnections = child.getTargetConnections();
		redo();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.commands.Command#redo()
	 */
	public void redo() {
		// remove the child and disconnect its connections
		Object genericParent = (Object) parent;
		if (genericParent instanceof UMLDiagram)
			wasRemoved = ((UMLDiagram) genericParent).removeChild(child);
		else if (genericParent instanceof UMLStateMachine)
			wasRemoved = ((UMLStateMachine) genericParent)
					.removeStartState(child);
		if (wasRemoved) {
			removeConnections(sourceConnections);
			removeConnections(targetConnections);
		}
	}

	/**
	 * Disconnects a List of Connections from their endpoints.
	 * 
	 * @param connections
	 *            a non-null List of connections
	 */
	private void removeConnections(List<Connection> connections) {
		for (Iterator<Connection> iter = connections.iterator(); iter.hasNext();) {
			Connection conn = iter.next();
			conn.disconnect();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.commands.Command#undo()
	 */
	public void undo() {
		// add the child and reconnect its connections
		Object genericParent = (Object) parent;
		if (genericParent instanceof UMLDiagram) {
			if (((UMLDiagram) genericParent).addChild(child)) {
				addConnections(sourceConnections);
				addConnections(targetConnections);
			}
		} else if (genericParent instanceof UMLStateMachine) {
			if (((UMLStateMachine) genericParent).addStartState(child)) {
				addConnections(sourceConnections);
				addConnections(targetConnections);
			}
		}
	}
}
